package com.pwt.service;

import com.pwt.common.CustomException;
import com.pwt.common.DataNotFoundException;
import com.pwt.common.ResultCode;
import com.pwt.common.ResultPage;
import com.pwt.entity.*;
import com.pwt.model.UserGrantsModel;
import com.pwt.model.UserModel;
import com.pwt.model.UserPOJO;
import com.pwt.repository.RoleRepository;
import com.pwt.repository.UserRepository;
import com.pwt.security.utils.JWTUser;
import com.pwt.security.utils.JWTUtils;
import com.pwt.utils.BeanUtils;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

/**
 * User service层
 *
 * @author auto generated
 * @date 2021-08-27 15:18:32
 */
@Service
public class UserService {

    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;


    @Autowired
    UserRepository userRepository;

    @Autowired
    RoleRepository roleRepository;

    @Autowired
    JPAQueryFactory queryFactory;

    @Transactional(rollbackFor = Exception.class)
    public User add(User userAddModel) throws CustomException {
        String username = userAddModel.getUsername();
        String password = userAddModel.getPassword();
        if(StringUtils.isEmpty(password)){
            password = "123456";
        }
        int count = userRepository.countUserByUsername(username);
        if (count == 0) {
            User user = new User();
            BeanUtils.copyProperties(userAddModel, user);
            user.setUsername(username);
            user.setPassword(bCryptPasswordEncoder.encode(password));
            user = userRepository.save(user);
            String userId = user.getId();
            String[] roleIds = userAddModel.getRoles();
            for (String roleId : roleIds) {
                roleRepository.saveUserRole(userId, roleId, UUID.randomUUID().toString().replaceAll("-", ""));
            }
            return user;
        } else {
            throw new CustomException(ResultCode.DATA_EXISTED);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public User add(String username) throws CustomException {
        int count = userRepository.countUserByUsername(username);
        if (count == 0) {
            User user = new User();
            user.setUsername(username);
            user.setNickName(username);
            user = userRepository.save(user);
//            String userId = user.getId();
//            Role role = this.roleRepository.findBySign("system");
//            if(role != null  && role.getId() != null){
//                roleRepository.saveUserRole(userId, role.getId(), UUID.randomUUID().toString().replaceAll("-", ""));
//            }
            String[] roleIds = user.getRoles();
            roleRepository.deleteByUserId(user.getId());
            for (String roleId : roleIds) {
                roleRepository.saveUserRole(user.getId(), roleId, UUID.randomUUID().toString().replaceAll("-", ""));
            }
            return user;
        } else {
            throw new CustomException(ResultCode.DATA_EXISTED);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void grants(UserGrantsModel userGrantsModel) {
        String userId = userGrantsModel.getUserId();
        List<String> roleIds = userGrantsModel.getRoleIds();
        roleRepository.deleteByUserId(userId);
        for (String roleId : roleIds) {
            roleRepository.saveUserRole(userId, roleId, UUID.randomUUID().toString().replaceAll("-", ""));
        }
    }

    public ResultPage<UserPOJO> list(Integer limit, Integer page, String username, String nickName) {
        ResultPage<UserPOJO> resultPage = new ResultPage<>();
        QUser qUser = QUser.user;
        QUserRole qUserRole = QUserRole.userRole;
        QRole qRole = QRole.role;
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        if(username != null && StringUtils.isNotBlank(username)) {
            booleanBuilder.and(qUser.username.like(username));
        }
        if(StringUtils.isNotBlank(nickName)) {
            booleanBuilder.and(qUser.nickName.like(nickName));
        }
        long count = queryFactory.select(qUser.count()).from(qUser).where(booleanBuilder).fetchOne();
        if(count == 0) {
            return resultPage;
        }
        List<UserPOJO> list = queryFactory.select(Projections.bean(UserPOJO.class, qUser.id.as("id"), qUser.username, qUser.nickName,qUser.lastLoginTime,qUser.status,qRole.name.as("roleName")))
                .from(qUser).leftJoin(qUserRole).on(qUser.id.eq(qUserRole.userId))
                .leftJoin(qRole).on(qUserRole.roleId.eq(qRole.id)).where(booleanBuilder)
                .limit(limit).offset((page - 1) * limit).fetch();
        resultPage.setCurrentPage(page);
        resultPage.setTotalRow(count);
        resultPage.setPageSize(limit);
        resultPage.setData(list);
        resultPage.setTotalPage((int) (count/limit) + 1);
        return resultPage;
    }

    public UserPOJO user(String id) throws DataNotFoundException {
        QUser qUser = QUser.user;
        QUserRole qUserRole = QUserRole.userRole;
        QRole qRole = QRole.role;
        UserPOJO user = queryFactory.select(Projections.bean(UserPOJO.class, qUser.id.as("id"), qUser.username, qUser.nickName,qUser.lastLoginTime,qUser.status,qRole.name.as("roleName")))
                .from(qUser).leftJoin(qUserRole).on(qUser.id.eq(qUserRole.userId)).where(qUser.id.eq(id))
                .leftJoin(qRole).on(qUserRole.roleId.eq(qRole.id)).fetchOne();

        user.setRoles(this.roleRepository.getByUserId(id));
        if(user == null) {
            throw new DataNotFoundException(ResultCode.USER_NOT_EXIST);
        }
        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    public User edit(User user) throws CustomException {
        String username = user.getUsername();
        User user1 = userRepository.findByUsername(username);
        if(user1 != null) {
            if(!user1.getId().equals(user.getId())) {
                throw new CustomException(ResultCode.DATA_EXISTED);
            }
        }
        String[] roleIds = user.getRoles();
        roleRepository.deleteByUserId(user.getId());
        for (String roleId : roleIds) {
            roleRepository.saveUserRole(user.getId(), roleId, UUID.randomUUID().toString().replaceAll("-", ""));
        }
        if(StringUtils.isNotBlank(user.getPassword())){
            user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        }
        return userRepository.save(user);
    }

    @Transactional(rollbackFor = Exception.class)
    public String delete(String id) {
        roleRepository.deleteByUserId(id);
        userRepository.deleteById(id);
        return id;
    }

    public UserPOJO profile() throws DataNotFoundException {
        JWTUser jwtUser = JWTUtils.getToken();
        String username = jwtUser.getUsername();
        QUser qUser = QUser.user;
        QUserRole qUserRole = QUserRole.userRole;
        QRole qRole = QRole.role;
        UserPOJO userPOJO = queryFactory.select(Projections.bean(UserPOJO.class, qUser.id.as("id"), qUser.username, qUser.nickName,qUser.lastLoginTime,qUser.status,qRole.name.as("roleName")))
                .from(qUser).leftJoin(qUserRole).on(qUser.id.eq(qUserRole.userId)).where(qUser.username.eq(username))
                .leftJoin(qRole).on(qUserRole.roleId.eq(qRole.id)).fetchOne();
        if(userPOJO == null) {
            throw new DataNotFoundException(ResultCode.USER_NOT_EXIST);
        }
        return userPOJO;
    }
}
